/*
 * This file is part of aion-unique <aion-unique.com>.
 *
 *  aion-unique is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  aion-unique is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with aion-unique.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionemu.gameserver.model.gameobjects;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.apache.log4j.Logger;

import com.aionemu.commons.database.dao.DAOManager;
import com.aionemu.gameserver.configs.main.OptionsConfig;
import com.aionemu.gameserver.dao.ItemStoneListDAO;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.model.DescriptionId;
import com.aionemu.gameserver.model.IExpirable;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.gameobjects.player.Storage;
import com.aionemu.gameserver.model.gameobjects.player.StorageType;
import com.aionemu.gameserver.model.items.GodStone;
import com.aionemu.gameserver.model.items.ItemId;
import com.aionemu.gameserver.model.items.ItemMask;
import com.aionemu.gameserver.model.items.ItemStone.ItemStoneType;
import com.aionemu.gameserver.model.items.ItemStorage;
import com.aionemu.gameserver.model.items.ManaStone;
import com.aionemu.gameserver.model.templates.item.ArmorType;
import com.aionemu.gameserver.model.templates.item.EquipType;
import com.aionemu.gameserver.model.templates.item.GodstoneInfo;
import com.aionemu.gameserver.model.templates.item.ItemQuality;
import com.aionemu.gameserver.model.templates.item.ItemTemplate;
import com.aionemu.gameserver.model.templates.quest.QuestItems;
import com.aionemu.gameserver.network.aion.serverpackets.SM_ADD_ITEMS;
import com.aionemu.gameserver.network.aion.serverpackets.SM_DELETE_ITEM;
import com.aionemu.gameserver.network.aion.serverpackets.SM_DELETE_WAREHOUSE_ITEM;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.network.aion.serverpackets.SM_UPDATE_ITEM;
import com.aionemu.gameserver.network.aion.serverpackets.SM_UPDATE_WAREHOUSE_ITEM;
import com.aionemu.gameserver.network.aion.serverpackets.SM_WAREHOUSE_UPDATE;
import com.aionemu.gameserver.skillengine.model.IStatEffect;
import com.aionemu.gameserver.taskmanager.tasks.ExpireTimerTask;
import com.aionemu.gameserver.taskmanager.tasks.ItemUpdater;
import com.aionemu.gameserver.taskmanager.tasks.TemporaryTradeTimeTask;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.idfactory.IDFactory;

/**
 * @author ATracer, Lyahim
 */
public class Item extends AionObject implements IStatEffect, IExpirable
{
	private static Logger	log	= Logger.getLogger(Item.class);

	private enum eItemPacketEvent
	{
		DELETE, UPDATE, ADD
	}

	public static Item newItem(int itemId, long count)
	{
		return newItem(itemId, count, "");
	}

	/**
	 * @param itemId
	 * @param count
	 * @return
	 * 
	 *         Creates new Item instance. If count is greater than template maxStackCount, count value will be cut to
	 *         maximum allowed This method will return null if ItemTemplate for itemId was not found.
	 */
	public static Item newItem(int itemId, long count, String creator)
	{
		ItemTemplate itemTemplate = DataManager.ITEM_DATA.getItemTemplate(itemId);
		if (itemTemplate == null)
		{
			log.error("Item was not populated correctly. Item template is missing for item id: " + itemId);
			return null;
		}
		int maxStackCount = itemTemplate.getMaxStackCount();
		if (count > maxStackCount && maxStackCount != 0)
		{
			count = maxStackCount;
		}

		// TODO if Item object will contain ownerId - item can be saved to DB before return
		return new Item(0, IDFactory.getInstance().nextId(), itemTemplate, count, false, 0, creator);
	}

	/**
	 * Loads item stones from DB for each item in a list if item is ARMOR or WEAPON Godstones will be laoded for WEAPON
	 * items
	 * 
	 * @param itemList
	 */
	public static void loadItemStones(Collection<Item> itemList)
	{
		if (itemList == null)
			return;
		DAOManager.getDAO(ItemStoneListDAO.class).load(itemList);
	}

	/**
	 * Used to split item into 2 items
	 * 
	 * @param player
	 * @param itemObjId
	 * @param splitAmount
	 * @param slotNum
	 * @param sourceStorageType
	 * @param desetinationStorageType
	 */
	public static void splitItem(Player player, int itemObjId, long splitAmount, int slotNum, int sourceStorageType, int destinationStorageType)
	{
		Storage sourceStorage = player.getStorage(sourceStorageType);
		Storage destinationStorage = player.getStorage(destinationStorageType);

		Item itemToSplit = sourceStorage.getItemByObjId(itemObjId);
		if (itemToSplit == null)
		{
			itemToSplit = sourceStorage.getKinahItem();
			if (itemToSplit.getObjectId() != itemObjId || itemToSplit == null)
			{
				log.warn(String.format("CHECKPOINT: attempt to split null item %d %d %d", itemObjId, splitAmount, slotNum));
				return;
			}
		}

		if (sourceStorageType != destinationStorageType && !canMoveTo(player, itemToSplit, destinationStorageType))
			return;

		// To move kinah from inventory to warehouse and vise versa client using split item packet
		if (itemToSplit.getItemTemplate().isKinah())
		{
			if (!decreaseKinah(player, sourceStorage, splitAmount))
				return;
			increaseKinah(player, destinationStorage, splitAmount);
			return;
		}

		long oldItemCount = itemToSplit.getItemCount() - splitAmount;

		if (itemToSplit.getItemCount() < splitAmount || oldItemCount == 0)
			return;

		Item newItem = newItem(itemToSplit.getItemId(), splitAmount);
		newItem.setEquipmentSlot(slotNum);

		if (addFullItem(player, destinationStorage, newItem, false))
		{
			decreaseItemCount(player, sourceStorage, itemToSplit, splitAmount);
		}
	}

	public static boolean canMoveTo(Player player, Item item, int targetStore)
	{
		boolean can = true;
		switch (targetStore)
		{
			case 1:
			case 32:
			case 33:
			case 34:
			case 35:
				can = item.getItemTemplate().isStorableinCharWarehouse();
				break;
			case 2:
				can = item.getItemTemplate().isStorableinAccWarehouse();
			case 3:
				can = item.getItemTemplate().isStorableinLegionWarehouse();
		}
		if (!can)
		{
			log.info("[AUDIT]Client mod. Item: " + item.getItemId() + " store to : " + StorageType.getStorageTypeById(targetStore) + " Player:"
					+ player.getName());
			return false;
		}
		return true;
	}

	public static boolean decreaseKinah(Player player, long amount)
	{
		return decreaseKinah(player, player.getInventory(), amount);
	}

	public static boolean decreaseKinah(Player player, Storage storage, long amount)
	{
		boolean operationResult = storage.decreaseKinah(amount);
		if (operationResult)
		{
			sendItemPacket(eItemPacketEvent.UPDATE, player, storage.getStorageType(), storage.getKinahItem());
		}
		return operationResult;
	}

	public static void increaseItemCount(Player player, Storage storage, Item item, long amount)
	{
		item.increaseItemCount(amount);
		sendItemPacket(eItemPacketEvent.UPDATE, player, storage.getStorageType(), item);
	}

	public static void increaseKinah(Player player, Storage storage, long amount)
	{
		storage.increaseKinah(amount);
		sendItemPacket(eItemPacketEvent.UPDATE, player, storage.getStorageType(), storage.getKinahItem());
	}

	public static long decreaseItemCount(Player player, Item item, long count)
	{
		return decreaseItemCount(player, player.getInventory(), item, count);
	}

	/**
	 * Used to reduce item count in bag or completely remove by ITEMID This method operates in iterative manner overl
	 * all items with specified ITEMID. Return value can be the following: - true - item removal was successfull - false
	 * - not enough amount of items to reduce or item is not present
	 * 
	 * @param itemId
	 * @param count
	 * @return true or false
	 */
	public static boolean decreaseItemCountByItemId(Player player, int itemId, long count)
	{
		if (count < 1)
			return false;

		List<Item> items = player.getInventory().getItemsByItemId(itemId);

		for (Item item : items)
		{
			count = decreaseItemCount(player, player.getInventory(), item, count);

			if (count == 0)
				break;
		}
		return count == 0;
	}

	public static void increaseKinah(Player player, long amount)
	{
		increaseKinah(player, player.getInventory(), amount);
	}

	public static long decreaseItemCount(Player player, Storage storage, Item item, long count)
	{
		if (storage.getItemByObjId(item.getObjectId()) == null)
		{
			log.info("[AUDIT]Posible client hack. decreaseItemCount item not in storage " + player.getName());
			return count;
		}
		long itemCount = item.getItemCount();
		if (itemCount > count)
		{
			item.decreaseItemCount(count);
			sendItemPacket(eItemPacketEvent.UPDATE, player, storage.getStorageType(), item);
			return 0;
		}
		else if (itemCount <= count)
		{
			removeItem(player, storage, item, true);
			count -= itemCount;
			return count;
		}
		return count;
	}

	public static boolean removeItemFromInventory(Player player, Item item, boolean persist)
	{
		return removeItem(player, player.getInventory(), item, persist);
	}

	public static boolean removeItemFromInventoryByItemId(Player player, int itemId)
	{
		Storage storage = player.getInventory();
		boolean sucess = false;
		List<Item> items = storage.getItemsByItemId(itemId);

		for (Item item : items)
		{
			sucess |= removeItem(player, player.getInventory(), item, true);
		}
		return sucess;
	}

	public static boolean removeItemFromInventory(Player player, Item item)
	{
		return removeItem(player, player.getInventory(), item, true);
	}

	public static boolean removeItem(Player player, Storage storage, Item item, boolean persist)
	{
		return removeItem(player, storage, item, persist, true);
	}

	/**
	 * Used to remove item in inventory or completely remove by OBJECTID Return value can be the following: - true -
	 * item removal was successfull - false - not enough amount of items to reduce or item is not present
	 * 
	 * @param player
	 * @param itemObjId
	 * @return
	 */
	public static boolean removeItem(Player player, Storage storage, Item item, boolean persist, boolean sendPacket)
	{
		if (item == null)
		{ // the item doesn't exist, return false if the count is bigger then 0.
			log.warn("An item from player '" + player.getName() + "' that should be removed doesn't exist.");
			return false;
		}
		ExpireTimerTask.getInstance().removeExpirable(item);
		storage.removeFromBag(item, persist);
		if (sendPacket)
			sendItemPacket(eItemPacketEvent.DELETE, player, storage.getStorageType(), item);
		return true;
	}

	/**
	 * Used to reduce item count in inventory or completely remove by OBJECTID Return value can be the following: - true
	 * - item removal was successfull - false - not enough amount of items to reduce or item is not present
	 * 
	 * @param player
	 * @param itemObjId
	 * @param count
	 * @return
	 */
	public static boolean removeItemByObjectId(Player player, int itemObjId, boolean persist)
	{
		return removeItemByObjectId(player, player.getInventory(), itemObjId, persist);
	}

	/**
	 * Used to reduce item count in bag or completely remove by OBJECTID Return value can be the following: - true -
	 * item removal was successfull - false - not enough amount of items to reduce or item is not present
	 * 
	 * @param player
	 * @param storage
	 * @param itemObjId
	 * @param count
	 * @return
	 */
	public static boolean removeItemByObjectId(Player player, Storage storage, int itemObjId, boolean persist)
	{
		Item item = storage.getItemByObjId(itemObjId);
		if (item == null)
		{ // the item doesn't exist, return false if the count is bigger then 0.
			log.warn("An item from player '" + player.getName() + "' that should be removed doesn't exist.");
			return false;
		}
		return removeItem(player, storage, item, persist);
	}

	/**
	 * Used to merge 2 items in inventory
	 * 
	 * @param player
	 * @param sourceItemObjId
	 * @param itemAmount
	 * @param destinationObjId
	 */
	public static void mergeItems(Player player, int sourceItemObjId, long itemAmount, int destinationObjId, int sourceStorageType, int destinationStorageType)
	{
		if (itemAmount < 1)
		{
			log.info("[AUDIT]Merge item hack. itemAmount < 1. " + player.getName());
			return;
		}

		if (sourceItemObjId == destinationObjId)
			return;

		Storage sourceStorage = player.getStorage(sourceStorageType);
		Storage destinationStorage = player.getStorage(destinationStorageType);

		Item sourceItem = sourceStorage.getItemByObjId(sourceItemObjId);
		Item destinationItem = destinationStorage.getItemByObjId(destinationObjId);

		if (sourceItem == null || destinationItem == null)
			return; // Invalid object id provided

		if (sourceItem.getItemTemplate().getTemplateId() != destinationItem.getItemTemplate().getTemplateId())
			return; // Invalid item type

		if (sourceItem.getItemCount() < itemAmount)
			return; // Invalid item amount
		if (sourceStorageType != destinationStorageType)
		{
			boolean can = true;
			switch (sourceStorageType)
			{
				case 1:
				case 32:
				case 33:
				case 34:
				case 35:
					can = sourceItem.getItemTemplate().isStorableinCharWarehouse();
					break;
				case 2:
					can = sourceItem.getItemTemplate().isStorableinAccWarehouse();
				case 3:
					can = sourceItem.getItemTemplate().isStorableinLegionWarehouse();
			}
			if (!can)
			{
				log.info("[AUDIT]Client mod. Item: " + sourceItem.getItemId() + " store to : " + StorageType.getStorageTypeById(sourceStorageType) + " Player:"
						+ player.getName());
				return;
			}
		}
		if (decreaseItemCount(player, sourceStorage, sourceItem, itemAmount) == 0)
			increaseItemCount(player, destinationStorage, destinationItem, itemAmount);
	}

	public static void switchStoragesItems(Player player, int sourceStorageType, int sourceItemObjId, int replaceStorageType, int replaceItemObjId)
	{
		Storage sourceStorage = player.getStorage(sourceStorageType);
		Storage replaceStorage = player.getStorage(replaceStorageType);

		Item sourceItem = sourceStorage.getItemByObjId(sourceItemObjId);
		if (sourceItem == null)
			return;

		Item replaceItem = replaceStorage.getItemByObjId(replaceItemObjId);
		if (replaceItem == null)
			return;

		if (sourceStorageType != replaceStorageType && !canMoveTo(player, sourceItem, replaceStorageType)
													&& !canMoveTo(player, replaceItem, sourceStorageType))
			return;

		int sourceSlot = sourceItem.getEquipmentSlot();
		int replaceSlot = replaceItem.getEquipmentSlot();

		sourceItem.setEquipmentSlot(replaceSlot);
		replaceItem.setEquipmentSlot(sourceSlot);
		removeItem(player, sourceStorage, sourceItem, false);
		removeItem(player, replaceStorage, replaceItem, false);

		addFullItem(player, sourceStorage, replaceItem);
		addFullItem(player, replaceStorage, sourceItem);
	}

	/**
	 * Adds item count to player inventory I moved this method to service cause right implementation of it is critical
	 * to server operation and could cause starvation of object ids.
	 * 
	 * This packet will send necessary packets to client (initialize used only from quest engine
	 * 
	 * @param player
	 * @param itemId
	 * @param count
	 *            - amount of item that were not added to player's inventory
	 */
	public static boolean addItem(Player player, int itemId, long count, String creator, List<Integer> playersObjId)
	{
		if (count < 1)
			return false;
		if (OptionsConfig.LOG_ITEM)
			log.info(String.format("[ITEM] ID/Count - %d/%d to player %s.", itemId, count, player.getName()));
		if (itemId == ItemId.KINAH.value())
		{
			increaseKinah(player, count);
			return true;
		}
		Item item = newItem(itemId, count, creator);
		if (item == null)
			return false;
		ItemTemplate itemTemplate = DataManager.ITEM_DATA.getItemTemplate(itemId);
		if (playersObjId != null && itemTemplate.getTemporaryExchangeTime() != 0)
		{
			item.setTemporaryExchangeTime((int) (System.currentTimeMillis() / 1000) + (itemTemplate.getTemporaryExchangeTime() * 60));
			TemporaryTradeTimeTask.getInstance().addTask(item, playersObjId);
		}
		if (item.getExpireTime() != 0)
		{
			ExpireTimerTask.getInstance().addTask(item, player);
		}
		return addFullItem(player, player.getInventory(), item, true);
	}

	public static boolean addItem(Player player, int itemId, long count, String creator)
	{
		return addItem(player, itemId, count, creator, null);
	}

	public static boolean addItem(Player player, int itemId, long count)
	{
		return addItem(player, itemId, count, "");
	}

	public static boolean addFullItem(Player player, Storage storage, Item item)
	{
		return addFullItem(player, storage, item, true);
	}

	/**
	 * @param player
	 * @param itemId
	 * @param count
	 * @param manastones
	 * @param godStone
	 * @param enchantLevel
	 */
	public static boolean addFullItem(Player player, Storage storage, Item item, boolean merge)
	{
		ItemTemplate itemTemplate = item.getItemTemplate();
		if (itemTemplate == null)
			return false;

		int maxStackCount = itemTemplate.getMaxStackCount();
		int itemId = item.getItemId();

		if (itemId == ItemId.KINAH.value())
		{
			increaseKinah(player, item.getItemCount());
			return true;
		}

		if (merge)
		{
			/**
			 * Increase count of existing items
			 */
			List<Item> existingItems = storage.getAllItemsByItemId(itemId); // look for existing in equipment. need for
			// power shards.
			for (Item existingItem : existingItems)
			{
				if (item.getItemCount() < 1)
					break;

				long freeCount = maxStackCount - existingItem.getItemCount();
				if (item.getItemCount() <= freeCount)
				{
					increaseItemCount(player, storage, existingItem, item.getItemCount());
					item.setItemCount(0);
				}
				else
				{
					increaseItemCount(player, storage, existingItem, freeCount);
					item.decreaseItemCount(freeCount);
				}
			}
		}
		/**
		 * Create new stacks
		 */

		while (!storage.isFull() && item.getItemCount() > 0)
		{
			// item count still more than maxStack value
			if (item.getItemCount() > maxStackCount)
			{
				Item newItem = newItem(itemId, maxStackCount);
				item.decreaseItemCount(maxStackCount);
				storage.putToBag(newItem);
				sendItemPacket(eItemPacketEvent.ADD, player, storage.getStorageType(), newItem);
			}
			else
			{
				storage.putToBag(item);
				sendItemPacket(eItemPacketEvent.ADD, player, storage.getStorageType(), item);
				return true;
			}
		}

		if (storage.isFull() && item.getItemCount() > 0)
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_MSG_DICE_INVEN_ERROR);
			return false;
		}

		if (item.getItemCount() < 1)
		{
			item.setPersistentState(PersistentState.DELETED);
			ItemUpdater.getInstance().add(item);
		}
		return true;
	}

	public static void moveItem(Player player, int itemObjId, int sourceStorageType, int destinationStorageType, int slot)
	{
		Storage sourceStorage = player.getStorage(sourceStorageType);
		Item item = player.getStorage(sourceStorageType).getItemByObjId(itemObjId);

		if (item == null)
			return;

		if (sourceStorageType == destinationStorageType)
		{
			item.setEquipmentSlot(slot);
			sourceStorage.setPersistentState(PersistentState.UPDATE_REQUIRED);
			return;
		}
		if (!canMoveTo(player, item, destinationStorageType))
			return;
		Storage destinationStorage = player.getStorage(destinationStorageType);

		if (removeItem(player, sourceStorage, item, false))
			addFullItem(player, destinationStorage, item);
	}

	private static void sendItemPacket(eItemPacketEvent event, Player player, int storageType, Item item)
	{
		if (storageType == StorageType.CUBE.getId())
		{
			switch (event)
			{
				case ADD:
				{
					PacketSendUtility.sendPacket(player, new SM_ADD_ITEMS(Collections.singletonList(item)));
					break;
				}
				case DELETE:
				{
					PacketSendUtility.sendPacket(player, new SM_DELETE_ITEM(item.getObjectId()));
					break;
				}
				case UPDATE:
				{
					PacketSendUtility.sendPacket(player, new SM_UPDATE_ITEM(item));
					break;
				}
			}
		}
		else
		{
			switch (event)
			{
				case ADD:
				{
					PacketSendUtility.sendPacket(player, new SM_WAREHOUSE_UPDATE(item, storageType));
					break;
				}
				case DELETE:
				{
					PacketSendUtility.sendPacket(player, new SM_DELETE_WAREHOUSE_ITEM(storageType, item.getObjectId()));
					break;
				}
				case UPDATE:
				{
					PacketSendUtility.sendPacket(player, new SM_UPDATE_WAREHOUSE_ITEM(item, storageType));
					break;
				}
			}
		}
	}

	public static ManaStone addManaStone(Item item, int itemId, boolean fusionSlot)
	{
		if (item == null)
			return null;
		Set<ManaStone> manaStones;
		if (fusionSlot)
			manaStones = item.getFusionStones();
		else
			manaStones = item.getItemStones();

		// temp fix for manastone spam till templates are updated
		if (manaStones.size() >= item.getSockets(fusionSlot))
		{
			return null;
		}

		int nextSlot = 0;
		boolean slotFound = false;

		Iterator<ManaStone> iterator = manaStones.iterator();
		while (iterator.hasNext())
		{
			ManaStone manaStone = iterator.next();
			if (nextSlot != manaStone.getSlot())
			{
				slotFound = true;
				break;
			}
			nextSlot++;
		}

		if (!slotFound)
			nextSlot = manaStones.size();

		ManaStone stone = new ManaStone(item.getObjectId(), itemId, nextSlot, fusionSlot ? ItemStoneType.FUSION_MANASTONE : ItemStoneType.MANASTONE,
				PersistentState.NEW);
		manaStones.add(stone);
		DAOManager.getDAO(ItemStoneListDAO.class).store(Collections.singleton(stone), fusionSlot);
		return stone;
	}

	public static void removeManastone(Player player, int itemObjId, int slotNum, boolean fusionSlot)
	{
		Storage inventory = player.getInventory();
		Item item = inventory.getItemByObjId(itemObjId);
		if (item == null)
			item = player.getEquipment().getEquippedItemByObjId(itemObjId);
		if (item == null)
		{
			log.warn("Item not found during manastone remove");
			return;
		}

		Set<ManaStone> itemStones = null;
		if (fusionSlot)
			itemStones = item.getFusionStones();
		else
			itemStones = item.getItemStones();

		if (itemStones == null)
		{
			log.warn("Item stone list is empty");
			return;
		}

		if (itemStones.size() <= slotNum)
			return;

		int counter = 0;
		Iterator<ManaStone> iterator = itemStones.iterator();
		while (iterator.hasNext())
		{
			ManaStone manaStone = iterator.next();
			if (counter == slotNum)
			{
				manaStone.setPersistentState(PersistentState.DELETED);
				iterator.remove();
				DAOManager.getDAO(ItemStoneListDAO.class).store(Collections.singleton(manaStone), fusionSlot);
				break;
			}
			counter++;
		}
		PacketSendUtility.sendPacket(player, new SM_UPDATE_ITEM(item));
	}

	public static void removeAllManastone(Player player, Item item, boolean fusionSlot)
	{
		if (item == null)
		{
			log.warn("Item not found during manastone remove");
			return;
		}
		Set<ManaStone> itemStones = null;
		if (fusionSlot)
		{
			if (item.hasFusionStones())
				itemStones = item.getFusionStones();
		}
		else
		{
			if (item.hasManaStones())
				itemStones = item.getItemStones();
		}

		if (itemStones == null)
			return;

		Iterator<ManaStone> iterator = itemStones.iterator();
		while (iterator.hasNext())
		{
			ManaStone manaStone = iterator.next();
			manaStone.setPersistentState(PersistentState.DELETED);
			iterator.remove();
			DAOManager.getDAO(ItemStoneListDAO.class).store(Collections.singleton(manaStone), false);
		}
	}

	public static void socketGodstone(Player player, int weaponId, int stoneId)
	{
		long socketPrice = player.getPrices().getPriceForService(100000);

		Item weaponItem = player.getInventory().getItemByObjId(weaponId);
		if (weaponItem == null)
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_GIVE_ITEM_PROC_CANNOT_GIVE_PROC_TO_EQUIPPED_ITEM);
			return;
		}

		Item godstone = player.getInventory().getItemByObjId(stoneId);

		int godStoneItemId = godstone.getItemTemplate().getTemplateId();
		ItemTemplate itemTemplate = DataManager.ITEM_DATA.getItemTemplate(godStoneItemId);
		GodstoneInfo godstoneInfo = itemTemplate.getGodstoneInfo();

		if (godstoneInfo == null)
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_GIVE_ITEM_PROC_NO_PROC_GIVE_ITEM);
			log.warn("Godstone info missing for itemid " + godStoneItemId);
			return;
		}

		if (!decreaseKinah(player, socketPrice))
			return;
		weaponItem.addGodStone(godStoneItemId);
		PacketSendUtility.sendPacket(player,
				SM_SYSTEM_MESSAGE.STR_GIVE_ITEM_PROC_ENCHANTED_TARGET_ITEM(new DescriptionId(Integer.parseInt(weaponItem.getName()))));
		decreaseItemCount(player, godstone, 1);

		PacketSendUtility.sendPacket(player, new SM_UPDATE_ITEM(weaponItem));
	}

	public static boolean addItems(Player player, List<QuestItems> questItems)
	{
		int needSlot = 0;
		for (QuestItems qi : questItems)
		{
			if (qi.getItemId() != ItemId.KINAH.value() && qi.getCount() != 0)
			{
				int stackCount = DataManager.ITEM_DATA.getItemTemplate(qi.getItemId()).getMaxStackCount();
				int count = qi.getCount() / stackCount;
				if (qi.getCount() % stackCount != 0)
					count++;
				needSlot += count;
			}
		}
		if (needSlot > player.getInventory().getNumberOfFreeSlots())
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.MSG_FULL_INVENTORY);
			return false;
		}
		for (QuestItems qi : questItems)
			addItem(player, qi.getItemId(), qi.getCount());
		return true;
	}

	public static void restoreKinah(Player player)
	{
		// if kinah was deleted by some reason it should be restored with 0 count
		if (player.getStorage(StorageType.CUBE.getId()).getKinahItem() == null)
		{
			Item kinahItem = newItem(182400001, 0);
			kinahItem.setOwnerId(player.getObjectId());
			onLoadHandler(player, player.getStorage(StorageType.CUBE.getId()), kinahItem);
		}

		if (player.getStorage(StorageType.ACCOUNT_WAREHOUSE.getId()).getKinahItem() == null)
		{
			Item kinahItem = newItem(182400001, 0);
			kinahItem.setOwnerId(player.getStorage(StorageType.ACCOUNT_WAREHOUSE.getId()).getOwnerId());
			kinahItem.setItemLocation(StorageType.ACCOUNT_WAREHOUSE.getId());
			onLoadHandler(player, player.getStorage(StorageType.ACCOUNT_WAREHOUSE.getId()), kinahItem);
		}
	}

	public static void onLoadHandler(Player player, Storage storage, Item item)
	{
		if (player != null && item.isEquipped())
		{
			player.getEquipment().onLoadHandler(item);
		}
		else if (item.getItemTemplate().isKinah())
		{
			storage.setKinahItem(item);
		}
		else
		{
			storage.putToNextAvailableSlot(item);
		}
	}

	public static void remodelItem(Player player, int keepItemObjId, int extractItemObjId)
	{
		Storage inventory = player.getInventory();
		Item keepItem = inventory.getItemByObjId(keepItemObjId);
		Item extractItem = inventory.getItemByObjId(extractItemObjId);

		long remodelCost = player.getPrices().getPriceForService(1000);

		if (keepItem == null || extractItem == null)
		{ // NPE check.
			return;
		}

		// Check Player Level
		if (player.getLevel() < 20)
		{

			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_CHANGE_ITEM_SKIN_PC_LEVEL_LIMIT);
			return;
		}

		// Check for using "Pattern Reshaper" (168100000)
		if (extractItem.getItemTemplate().getTemplateId() == 168100000)
		{
			if (keepItem.getItemTemplate() == keepItem.getItemSkinTemplate())
			{
				PacketSendUtility.sendMessage(player, "That item does not have a remodeled skin to remove.");
				return;
			}

			// Check Kinah
			if (!decreaseKinah(player, remodelCost))
			{
				PacketSendUtility.sendPacket(player,
						SM_SYSTEM_MESSAGE.STR_CHANGE_ITEM_SKIN_NOT_ENOUGH_GOLD(new DescriptionId(keepItem.getItemTemplate().getNameId())));
				return;
			}

			// Remove Pattern Reshaper
			decreaseItemCount(player, extractItem, 1);

			// Revert item to ORIGINAL SKIN
			keepItem.setItemSkinTemplate(keepItem.getItemTemplate());

			// Remove dye color if item can not be dyed.
			if (!keepItem.getItemTemplate().isCanDye())
				keepItem.setItemColor(0);

			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_CHANGE_ITEM_SKIN_SUCCEED(new DescriptionId(keepItem.getItemTemplate().getNameId())));

			return;
		}
		// Check that types match.
		if (keepItem.getItemTemplate().getWeaponType() != extractItem.getItemSkinTemplate().getWeaponType()
				|| (extractItem.getItemSkinTemplate().getArmorType() != ArmorType.CLOTHES && keepItem.getItemTemplate().getArmorType() != extractItem
						.getItemSkinTemplate().getArmorType()) || keepItem.getItemTemplate().getArmorType() == ArmorType.CLOTHES
				|| keepItem.getItemTemplate().getItemSlot() != extractItem.getItemSkinTemplate().getItemSlot())
		{
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_CHANGE_ITEM_SKIN_NOT_COMPATIBLE(
					new DescriptionId(keepItem.getItemTemplate().getNameId()), new DescriptionId(extractItem.getItemSkinTemplate().getNameId())));
			return;
		}

		if (!extractItem.getItemTemplate().isChangeSkinPermitted())
		{
			PacketSendUtility.sendPacket(player, new SM_SYSTEM_MESSAGE(1300482, new DescriptionId(extractItem.getItemTemplate().getNameId())));
			return;
		}

		// -- SUCCESS --
		// Check Kinah
		if (!decreaseKinah(player, remodelCost))
		{
			PacketSendUtility.sendPacket(player,
					SM_SYSTEM_MESSAGE.STR_CHANGE_ITEM_SKIN_NOT_ENOUGH_GOLD(new DescriptionId(keepItem.getItemTemplate().getNameId())));
			return;
		}

		// Remove Pattern Reshaper
		decreaseItemCount(player, extractItem, 1);

		// REMODEL ITEM
		keepItem.setItemSkinTemplate(extractItem.getItemSkinTemplate());

		// Transfer Dye
		keepItem.setItemColor(extractItem.getItemColor());

		PacketSendUtility.sendPacket(player, new SM_SYSTEM_MESSAGE(1300483, new DescriptionId(keepItem.getItemTemplate().getNameId())));
	}

	private long			itemCount						= 1;

	private int				ownerId							= 0;
	private int				itemColor						= 0;

	private ItemTemplate	itemTemplate;
	private ItemTemplate	itemSkinTemplate;

	private boolean			isEquipped						= false;

	private int				equipmentSlot					= ItemStorage.FIRST_AVAILABLE_SLOT;

	private PersistentState	persistentState;

	private Set<ManaStone>	manaStones;

	private GodStone		godStone;

	private boolean			isSoulBound						= false;

	private int				itemLocation;

	private int				enchantLevel;

	private int				fusionedItemId;

	private int				optionalManastoneSocket			= 0;

	private int				optionalFusionedManastoneSocket	= 0;

	private Set<ManaStone>	fusionedManaStones;

	private int				expireTime						= 0;

	private int				temporaryExchangeTime			= 0;

	private String			creator							= "";

	/**
	 * @param ownerId
	 * @param objId
	 * @param itemTemplate
	 * @param itemCount
	 * @param isEquipped
	 * @param equipmentSlot
	 * 
	 * This constructor should be called from ItemService
	 * for newly created items and loadedFromDb
	 */
	public Item(int ownerId, int objId, ItemTemplate itemTemplate, long itemCount, boolean isEquipped, int equipmentSlot, String creator)
	{
		super(objId);
		this.ownerId = ownerId;
		this.creator = creator;
		this.itemTemplate = itemTemplate;
		this.itemCount = itemCount;
		this.isEquipped = isEquipped;
		this.equipmentSlot = equipmentSlot;
		this.persistentState = PersistentState.NEW;
		if (itemTemplate.getExpireTime() != 0)
		{
			expireTime = ((int) (System.currentTimeMillis() / 1000) + itemTemplate.getExpireTime() * 60) - 1;
		}
		if (ownerId != 0)
			ItemUpdater.getInstance().add(this);
	}

	/**
	 * @param objId
	 * @param itemId
	 * @param itemCount
	 * @param isEquipped
	 * @param equipmentSlot
	 * 
	 * This constructor should be called only from DAO while loading from DB
	 */
	public Item(int ownerId, int objId, int itemId, long itemCount, int itemColor, boolean isEquipped, boolean isSoulBound, int equipmentSlot,
			int itemLocation, int enchant, int itemSkin, int fusionedItem, int expireTime, String creator)
	{
		super(objId);
		this.ownerId = ownerId;
		this.itemTemplate = DataManager.ITEM_DATA.getItemTemplate(itemId);
		this.itemCount = itemCount;
		this.itemColor = itemColor;
		this.isEquipped = isEquipped;
		this.isSoulBound = isSoulBound;
		this.equipmentSlot = equipmentSlot;
		this.itemLocation = itemLocation;
		this.enchantLevel = enchant;
		this.fusionedItemId = fusionedItem;
		this.itemSkinTemplate = DataManager.ITEM_DATA.getItemTemplate(itemSkin);
		this.expireTime = expireTime;
		this.creator = creator;
	}

	/**
	 * @return the ownerId
	 */
	public int getOwnerId()
	{
		return ownerId;
	}

	/**
	 * @param ownerId the ownerId to set
	 */
	public void setOwnerId(int ownerId)
	{
		this.ownerId = ownerId;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	@Override
	public String getName()
	{
		//TODO
		//item description should return probably string and not id
		return String.valueOf(itemTemplate.getNameId());
	}

	public String getItemName()
	{
		return itemTemplate.getName();
	}

	/**
	 * @return the itemTemplate
	 */
	public ItemTemplate getItemTemplate()
	{
		return itemTemplate;
	}

	/**
	 * @return the itemAppearanceTemplate
	 */
	public ItemTemplate getItemSkinTemplate()
	{
		if (this.itemSkinTemplate == null)
			return this.itemTemplate;
		return this.itemSkinTemplate;
	}

	public void setItemSkinTemplate(ItemTemplate newTemplate)
	{
		this.itemSkinTemplate = newTemplate;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	/**
	 *@return the itemColor
	 */
	public int getItemColor()
	{
		return itemColor;
	}

	/**
	 * @param itemColor the itemColor to set
	 */
	public void setItemColor(int itemColor)
	{
		this.itemColor = itemColor;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	/**
	 * @param itemTemplate the itemTemplate to set
	 */
	public void setItemTemplate(ItemTemplate itemTemplate)
	{
		this.itemTemplate = itemTemplate;
	}

	/**
	 * @return the itemCount
	 *  Number of this item in stack. Should be not more than template maxstackcount ?
	 */
	public long getItemCount()
	{
		return itemCount;
	}

	/**
	 * @param itemCount the itemCount to set
	 */
	public void setItemCount(long itemCount)
	{
		this.itemCount = itemCount;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	/**
	 *  This method should be called ONLY from Storage class
	 *  In all other ways it is not guaranteed to be udpated in a regular update service
	 *  It is allowed to use this method for newly created items which are not yet in any storage 
	 *  
	 * @param addCount 
	 */
	public void increaseItemCount(long addCount)
	{
		//TODO overflow check
		this.itemCount += addCount;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	/**
	 *  This method should be called ONLY from Storage class
	 *  In all other ways it is not guaranteed to be udpated in a regular update service
	 *  It is allowed to use this method for newly created items which are not yet in any storage 
	 *  
	 * @param remCount
	 */
	public boolean decreaseItemCount(long remCount)
	{
		if (this.itemCount - remCount >= 0)
		{
			this.itemCount -= remCount;
			if (itemCount == 0 && !this.itemTemplate.isKinah())
			{
				setPersistentState(PersistentState.DELETED);
			}
			else
			{
				setPersistentState(PersistentState.UPDATE_REQUIRED);
			}
			return true;
		}

		return false;
	}

	/**
	 * @return the isEquipped
	 */
	public boolean isEquipped()
	{
		return isEquipped;
	}

	/**
	 * @param isEquipped the isEquipped to set
	 */
	public void setEquipped(boolean isEquipped)
	{
		this.isEquipped = isEquipped;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	/**
	 * @return the equipmentSlot
	 *  Equipment slot can be of 2 types - one is the ItemSlot enum type if equipped, second - is position in cube
	 */
	public int getEquipmentSlot()
	{
		return equipmentSlot;
	}

	/**
	 * @param equipmentSlot the equipmentSlot to set
	 */
	public void setEquipmentSlot(int equipmentSlot)
	{
		this.equipmentSlot = equipmentSlot;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	/**
	 * This method should be used to lazy initialize empty manastone list
	 * @return the itemStones
	 */
	public Set<ManaStone> getItemStones()
	{
		if (manaStones == null)
			this.manaStones = new TreeSet<ManaStone>(new Comparator<ManaStone>()
			{

				@Override
				public int compare(ManaStone o1, ManaStone o2)
				{
					if (o1.getSlot() == o2.getSlot())
						return 0;
					return o1.getSlot() > o2.getSlot() ? 1 : -1;
				}

			});
		return manaStones;
	}

	/**
	 * Check manastones without initialization
	 * 
	 * @return
	 */
	public boolean hasManaStones()
	{
		return manaStones != null && manaStones.size() > 0;
	}

	/**
	 * @return the goodStone
	 */
	public GodStone getGodStone()
	{
		return godStone;
	}

	/**
	 * 
	 * @param itemId
	 * @return
	 */
	public GodStone addGodStone(int itemId)
	{
		PersistentState state = this.godStone != null ? PersistentState.UPDATE_REQUIRED : PersistentState.NEW;
		this.godStone = new GodStone(getObjectId(), itemId, state);
		DAOManager.getDAO(ItemStoneListDAO.class).store(godStone);
		return this.godStone;
	}

	/**
	 * @param goodStone the goodStone to set
	 */
	public void setGoodStone(GodStone goodStone)
	{
		this.godStone = goodStone;
	}

	/**
	 * @return the echantLevel
	 */
	public int getEnchantLevel()
	{
		return enchantLevel;
	}

	/**
	 * @param enchantLevel the echantLevel to set
	 */
	public void setEnchantLevel(int enchantLevel)
	{
		this.enchantLevel = enchantLevel;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	/**
	 * @return the persistentState
	 */
	public PersistentState getPersistentState()
	{
		return persistentState;
	}

	/**
	 *  Possible changes:
	 *  NEW -> UPDATED
	 *  NEW -> UPDATE_REQURIED
	 *  UPDATE_REQUIRED -> DELETED
	 *  UPDATE_REQUIRED -> UPDATED
	 *  UPDATED -> DELETED
	 *  UPDATED -> UPDATE_REQUIRED
	 * @param persistentState the persistentState to set
	 */
	public void setPersistentState(PersistentState persistentState)
	{
		if (persistentState != PersistentState.UPDATED && persistentState != PersistentState.NOACTION && ownerId != 0)
			ItemUpdater.getInstance().add(this);
		switch (persistentState)
		{
			case DELETED:
				if (this.persistentState == PersistentState.NEW)
					this.persistentState = PersistentState.NOACTION;
				else
					this.persistentState = PersistentState.DELETED;
				break;
			case UPDATE_REQUIRED:
				if (this.persistentState == PersistentState.NEW)
					break;
			default:
				this.persistentState = persistentState;
		}

	}

	public void setItemLocation(int storageType)
	{
		this.itemLocation = storageType;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	public int getItemLocation()
	{
		return itemLocation;
	}

	public int getItemMask()
	{
		return itemTemplate.getMask();
	}

	public boolean isSoulBound()
	{
		return isSoulBound;
	}

	/**
	 * 
	 * @return
	 */
	public boolean isTradeable()
	{
		return (getItemMask() & ItemMask.TRADEABLE) == ItemMask.TRADEABLE && !isSoulBound;
	}

	public void setSoulBound(boolean isSoulBound)
	{
		this.isSoulBound = isSoulBound;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	public EquipType getEquipmentType()
	{
		if (itemTemplate.isStigma())
			return EquipType.STIGMA;
		else
			return itemTemplate.getEquipmentType();
	}

	@Override
	public String toString()
	{
		return "Item [equipmentSlot=" + equipmentSlot + ", godStone=" + godStone + ", isEquipped=" + isEquipped + ", itemColor=" + itemColor + ", itemCount="
				+ itemCount + ", itemLocation=" + itemLocation + ", itemTemplate=" + itemTemplate + ", manaStones=" + manaStones + ", persistentState="
				+ persistentState + "]";
	}

	public int getItemId()
	{
		return itemTemplate.getTemplateId();
	}

	public int getNameID()
	{
		return itemTemplate.getNameId();
	}

	public boolean hasFusionedItem()
	{
		return (fusionedItemId != 0);
	}

	public int getFusionedItem()
	{
		return fusionedItemId;
	}

	public void setFusionedItem(int itemTemplateId)
	{
		fusionedItemId = itemTemplateId;
		setPersistentState(PersistentState.UPDATE_REQUIRED);
	}

	@Override
	public void finalize()
	{
		if (this.persistentState == PersistentState.NOACTION || this.persistentState == PersistentState.DELETED || ownerId == 0)
		{
			IDFactory.getInstance().releaseId(getObjectId());
		}
		try
		{
			super.finalize();
		}
		catch (Throwable e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * @return
	 */
	public Set<ManaStone> getFusionStones()
	{
		if (fusionedManaStones == null)
			this.fusionedManaStones = new TreeSet<ManaStone>(new Comparator<ManaStone>()
			{

				@Override
				public int compare(ManaStone o1, ManaStone o2)
				{
					if (o1.getSlot() == o2.getSlot())
						return 0;
					return o1.getSlot() > o2.getSlot() ? 1 : -1;
				}

			});
		return fusionedManaStones;
	}

	public void setFusionStones(Set<ManaStone> stones)
	{
		if (stones == null || stones.isEmpty())
			return;
		if (fusionedManaStones == null)
			this.fusionedManaStones = new TreeSet<ManaStone>(new Comparator<ManaStone>()
			{

				@Override
				public int compare(ManaStone o1, ManaStone o2)
				{
					if (o1.getSlot() == o2.getSlot())
						return 0;
					return o1.getSlot() > o2.getSlot() ? 1 : -1;
				}

			});
		for (ManaStone stone : stones)
		{
			fusionedManaStones.add(new ManaStone(getObjectId(), stone.getItemId(), stone.getSlot(), ItemStoneType.FUSION_MANASTONE, PersistentState.NEW));
		}
		fusionedManaStones = stones;
	}

	/**
	 * @return
	 */
	public boolean hasFusionStones()
	{
		return fusionedManaStones != null && fusionedManaStones.size() > 0;
	}

	/**
	 * @return
	 */
	public boolean hasOptionalFusionSocket()
	{
		return optionalFusionedManastoneSocket > 0;
	}

	/**
	 * @return
	 */
	public int getOptionalFusionSocket()
	{
		return optionalFusionedManastoneSocket;
	}

	/**
	 * @param i
	 */
	public void setOptionalFusionSocket(int i)
	{
		optionalFusionedManastoneSocket = i;
	}

	/**
	 * @return
	 */
	public boolean hasOptionalSocket()
	{
		return optionalManastoneSocket > 0;
	}

	/**
	 * @return
	 */
	public int getOptionalSocket()
	{
		return optionalManastoneSocket;
	}

	public void setOptionalSocket(int count)
	{
		optionalManastoneSocket = count;
	}

	private static int basicSocket(ItemQuality rarity)
	{
		switch (rarity)
		{
			case COMMON:
				return 1;
			case RARE:
				return 2;
			case LEGEND:
				return 3;
			case UNIQUE:
				return 4;
			case EPIC:
				return 5;
			default:
				return 1;
		}
	}

	private int extendedSocket(String type)
	{
		if (type.equalsIgnoreCase("ABYSS"))
			return 2;
		else
			return 0;
	}

	public int getSockets(boolean isFusionItem)
	{
		int numSockets;
		if (itemTemplate.isWeapon() || itemTemplate.isArmor())
		{
			if (isFusionItem)
			{
				ItemTemplate fusedTemp = DataManager.ITEM_DATA.getItemTemplate(getFusionedItem());
				numSockets = basicSocket(fusedTemp.getItemQuality());
				numSockets += extendedSocket(fusedTemp.getItemType());
				numSockets += hasOptionalFusionSocket() ? getOptionalFusionSocket() : 0;
			}
			else
			{
				numSockets = basicSocket(getItemTemplate().getItemQuality());
				numSockets += extendedSocket(getItemTemplate().getItemType());
				numSockets += hasOptionalSocket() ? getOptionalSocket() : 0;
			}
			if (numSockets < 6)
				return numSockets;
			return 6;
		}
		return 0;
	}

	/**
	 * @return Returns the expireTime.
	 */
	public int getExpireTime()
	{
		return expireTime;
	}

	public int getExpireTimeRemaining()
	{
		if (expireTime == 0)
			return 0;
		return expireTime - (int) (System.currentTimeMillis() / 1000);
	}

	/**
	 * @return Returns the temporaryExchangeTime.
	 */
	public int getTemporaryExchangeTime()
	{
		return temporaryExchangeTime;
	}

	public int getTemporaryExchangeTimeRemaining()
	{
		if (temporaryExchangeTime == 0)
			return 0;
		return temporaryExchangeTime - (int) (System.currentTimeMillis() / 1000);
	}

	/**
	 * @param temporaryExchangeTime The temporaryExchangeTime to set.
	 */
	public void setTemporaryExchangeTime(int temporaryExchangeTime)
	{
		this.temporaryExchangeTime = temporaryExchangeTime;
	}

	/**
	 * @return Returns the creator.
	 */
	public String getCreator()
	{
		return creator;
	}

	/* (non-Javadoc)
	 * @see com.aionemu.gameserver.model.IExpirable#expire()
	 */
	@Override
	public void expireEnd(Player player)
	{
		for (StorageType i : StorageType.values())
		{
			if (i == StorageType.LEGION_WAREHOUSE)
				continue;
			Storage storage = player.getStorage(i.getId());
			if (storage != null && storage.getItemByObjId(getObjectId()) != null)
			{
				Item.removeItem(player, storage, this, i == StorageType.CUBE);
				switch (i)
				{
					case CUBE:
						PacketSendUtility.sendPacket(player, new SM_SYSTEM_MESSAGE(1400034, new DescriptionId(getNameID())));
						break;
					case ACCOUNT_WAREHOUSE:
					case REGULAR_WAREHOUSE:
						PacketSendUtility.sendPacket(player, new SM_SYSTEM_MESSAGE(1400406, new DescriptionId(getNameID())));
				}
			}

		}
	}

	/* (non-Javadoc)
	 * @see com.aionemu.gameserver.model.IExpirable#expireMessage(int)
	 */
	@Override
	public void expireMessage(Player player, int time)
	{
		PacketSendUtility.sendPacket(player, new SM_SYSTEM_MESSAGE(1400481, new DescriptionId(getNameID()), time));
	}
}
